
package keul.planner.beans;

import java.io.Serializable;
import java.util.Collections;
import java.util.List;
import javax.annotation.PostConstruct;
import javax.annotation.PreDestroy;

import javax.ejb.Singleton;
import javax.ejb.Startup;


import javax.inject.Named;
import javax.persistence.EntityManager;
import javax.persistence.PersistenceContext;
import javax.persistence.TypedQuery;
import keul.planner.entities.City;
import keul.planner.entities.Line;
import keul.planner.entities.Station;
import keul.planner.tools.TestData;
import org.jgrapht.graph.DefaultDirectedWeightedGraph;
import org.jgrapht.graph.DefaultWeightedEdge;

/**
 * Hier stehen alle Entities global zur Verfügung
 * @author kev
 */
@Singleton
@Startup
@Named
/**
 * Diese Bean soll alle (für das Programm) statischen Daten liefern,
 * die es aus der Datenbank bezieht. Bereits bei Start des Application-
 * Servers sollen 
 * -Netz
 * -Stationen
 * -Linien, und
 * -(norddeutsche) Stätde
 * verfügbar sein
 */
public class DataManager implements Serializable{

    
    @PersistenceContext
    private EntityManager em;
    
    private List<City> cityListOfNorthernGermany;
    private List<Station> stationList;
    private DefaultDirectedWeightedGraph net;    
    private List<Line> lineList;
   
    public List<City> getCityList() {
        return cityListOfNorthernGermany;
    }
    public List<Station> getStationList() {
        return stationList;
    }
    public DefaultDirectedWeightedGraph getNet() { 
        return net;
    }
    public List<Line> getLineList() {
        return lineList;
    }
    

    /**
     * Hier werden die Datenbankabfragen getätigt, die nötig sind
     * um beim Start die Städte, Stationen, Linien und das Streckennetz
     * verfügbar zu machen.
     */
    @PostConstruct    
    private void postConstruct() {
        
        // CITTIES //
        TypedQuery<City> query = em.createQuery(
                "SELECT c FROM City c WHERE "
                + "c.longitude>8 AND "
                + "c.longitude<14 AND "
                + "c.latitude>50 AND "
                + "c.latitude<55",
                City.class);
        cityListOfNorthernGermany = query.getResultList();
        
        // STATIONS //
        stationList = (em.createQuery("select s from Station s", Station.class)).getResultList();
        
        
        // NET //  // ggf. EdgeFactory verwenden
        net = new DefaultDirectedWeightedGraph(DefaultWeightedEdge.class);
        for (Station station : stationList) {
            // Station selbst hinzufügen...
            net.addVertex(station);
        }
        for (Station station : stationList) {
            // Edges mit den Nachbarn schaffen...
            List<Station> neighbors = station.getNeighbors();
            for (Station neighbor : neighbors) {
                net.addEdge(station, neighbor);
            }
        }
        Collections.sort(stationList); // alphabetische Sortierung der Stationsliste
                
        // LINES //
        lineList = (em.createQuery("select l from Line l", Line.class)).getResultList();
        for(Line line : lineList) {
            line.putVerticesAndEdgesFromSuperGraph(net);  
        }
    }   
    /**
     * Das Gegenstück zu postConstruct. Die in der Methoden
     * belegten Variablen werden hier wieder auf <code>null</code> gesetzt.
     * @see postConstruct()
     */
    @PreDestroy
    private void preDestroy() {
        cityListOfNorthernGermany = null;
        stationList = null;
        net = null;
        lineList = null;
    }   
    

    /**
     * Gibt die Stadt zurück, die genau den übergebenen Namen besitzt.
     * @param name
     * @return 
     */
    public City getCityByName(String name) {
        for (City city : cityListOfNorthernGermany) {
            if (city.getName().equals(name))
                return city;
        }
        return null;
    }   
    /**
     * Gibt den Bahnhof zurück, die genau den übergebenen Namen besitzt.
     * @param name
     * @return 
     */
    public Station getStationByName(String name) {
        for (Station station : stationList) {
            if (station.getName().equals(name))
                return station;
        }
        return null;
    }
    /**
     * Gibt die Linie zurück, die genau den übergebenen Namen besitzt.
     * @param name
     * @return 
     */
    public Line getLineByName(String name) {
        for (Line line : lineList) {
            if (line.getName().equals(name))
                return line;
        }
        return null;
    }

    
    /**
     * Diese Methode gibt eine List aller Städte, die sich in
     * der Datenbank befinden, zurück.
     * @return 
     */
    public List<City> getAllAvailableCitiesInAList() {
        TypedQuery<City> query = em.createQuery("select c from City c", City.class);
        return query.getResultList();
    }
    
    /**
     * Um administrative Funktionen "vom View" aus aufrufen zu können
     * wird diese Methode zum Aufbauen der Datenbanktabellen verwendet.
     * @see keul.planner.tools.TestData.generateStationsAndLines
     */
    public void generateStationsAndLines() {
        TestData.generateStations(em);
        postConstruct();
    }
    /**
     * Um administrative Funktionen "vom View" aus aufrufen zu können
     * wird diese Methode zum Löschen der Datenbanktabellen verwendet.
     * @see keul.planner.tools.TestData.deleteStationsAndLines
     */
    public void deleteStationsAndLines() {
        TestData.deleteStationsAndLines(em);
        postConstruct();
    }
    
        

}
